﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Multitouch.Framework.WPF.Input;
using Multitouch.Framework.WPF;
using Project_CFT2.ViewModel;
using Project_CFT2.View;
using Project_CFT2.Factory;

namespace Project_CFT2.Behavior
{
    public class DropFurnitureBehaviour
    {
        private static readonly Dictionary<DoubleAnimation, FrameworkElement> AnimationViews =
            new Dictionary<DoubleAnimation, FrameworkElement>();

        private static readonly TimeSpan DefaultAnimationDuration = TimeSpan.FromSeconds(0.5);

        private static readonly List<Trash> Trashes = new List<Trash>();

        public static readonly List<Project_CFT2.View.RoomView> Rooms = new List<Project_CFT2.View.RoomView>();

        #region SourcePanel

        /// <summary>
        /// SourcePanel Attached Dependency Property
        /// </summary>
        
        public static readonly DependencyProperty SourcePanelProperty =
            DependencyProperty.RegisterAttached("SourcePanel", typeof (Panel), typeof (DropFurnitureBehaviour),
                                                new FrameworkPropertyMetadata(null,
                                                                              new PropertyChangedCallback(
                                                                                  OnSourcePanelChanged)));
        public static readonly DependencyProperty PanelViewFactoryProperty =
            DependencyProperty.RegisterAttached("PanelViewFactory", typeof(IPanelViewFactory), typeof(DropFurnitureBehaviour),
                                                new FrameworkPropertyMetadata(null, new PropertyChangedCallback(
                                                                                  OnSourcePanelChanged)));

        /// <summary>
        /// Gets the SourcePanel property.  This dependency property 
        /// indicates which panel uses this element as trash.
        /// </summary>
        public static Panel GetSourcePanel(DependencyObject d)
        {
            if (d == null)
                throw new ArgumentNullException("d");
            return (Panel) d.GetValue(SourcePanelProperty);
        }

        public static IPanelViewFactory GetPanelViewFactory(DependencyObject d)
        {
            if (d == null)
                throw new ArgumentNullException("d");
            return (IPanelViewFactory)d.GetValue(PanelViewFactoryProperty);
        }
        /// <summary>
        /// Sets the SourcePanel property.  This dependency property 
        /// indicates which panel uses this element as trash.
        /// </summary>
        public static void SetSourcePanel(DependencyObject d, Panel value)
        {
            if (d == null)
                throw new ArgumentNullException("d");
            d.SetValue(SourcePanelProperty, value);
        }

        /// <summary>
        /// Handles changes to the SourcePanel property.
        /// </summary>
        private static void OnSourcePanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

            var room = d as Project_CFT2.View.RoomView;
            if (room == null)
                throw new InvalidOperationException(
                    "The SourcePanel attached property can only be applied to RoomView controls.");

            var oldPanel = e.OldValue as Panel;
            if (oldPanel != null)
                MultitouchScreen.RemovePreviewContactRemovedHandler(oldPanel, SourcePanel_PreviewContactRemoved);

            var panel = e.NewValue as Panel;
            if (panel != null)
            {
                if (!Rooms.Contains(room)) Rooms.Add(room);
                MultitouchScreen.AddPreviewContactRemovedHandler(panel, SourcePanel_PreviewContactRemoved);
            }
            else
            {
                if (Rooms.Contains(room)) Rooms.Remove(room);
            }
        }

        #endregion
        
        private static void SourcePanel_PreviewContactRemoved(object sender, ContactEventArgs e)
        {
            var panel = (Panel) sender;



            var element = e.Contact.Captured as FrameworkElement;
            if (element is View.FurnitureObjectView || element is View.FurnitureObjectView2) // only if the item dropped is a furniture
            {
                foreach (Project_CFT2.View.RoomView room in Rooms)
                {
                    Rect roomRect = GetBoundingBox(room, panel);
                    Rect elementRoomIntersection = Rect.Intersect(GetBoundingBox(element, panel), roomRect);
                    var contactRect = new Rect(e.Contact.GetPosition(panel),
                                               new Size(e.Contact.BoundingRect.Width, e.Contact.BoundingRect.Height));
                    Rect contactRoomIntersection = Rect.Intersect(contactRect, roomRect);
                    if ((elementRoomIntersection.Width > 0 || elementRoomIntersection.Height > 0) &&
                        (contactRoomIntersection.Width > 0 || contactRoomIntersection.Height > 0) &&
                        panel.Children.Contains(element))
                    {



                        if (element is View.FurnitureObjectView)
                        {
                            room.AddItem(element.DataContext, e.GetPosition(room), panel);
                        }
                        else if (element is View.FurnitureObjectView2)
                        {
                            room.AddItem2(element.DataContext, e.GetPosition(room), panel);
                        }
                        RemoveView(panel, element, e.Contact.GetPosition(panel));
                        //room.Name = "mp2";
                        int x;
                        
                        //System.Threading.Thread.Sleep(7000);
                        /*IPanelViewFactory viewFactory = GetPanelViewFactory((DependencyObject)sender);
                        if (viewFactory == null) return;
                        var position = e.GetPosition(viewFactory.Panel);
                        var offset = e.GetPosition(viewFactory.Panel);
                        PanelBehavior.GetViewFactory((DependencyObject)panel).CreateViewFromDataContext2(element.DataContext, new Point(0, 100), panel);
                        viewFactory.CreateViewFromDataContext(new RoomViewModel(), new Point(position.X - offset.X, position.Y - offset.Y));
                         */
                        break;
                    }
                }
            }
        }


        private static Rect GetBoundingBox(FrameworkElement element, Visual visual)
        {
            GeneralTransform transform = element.TransformToVisual(visual);
            Point topLeft = transform.Transform(new Point(0, 0));
            Point bottomRight = transform.Transform(new Point(element.ActualWidth, element.ActualHeight));
            return new Rect(topLeft, bottomRight);
        }

        public static void RemoveView(Panel panel, FrameworkElement view, Point animationDestination)
        {
            RemoveView(panel, view, animationDestination, DefaultAnimationDuration);
        }

        public static void RemoveView(Panel panel, FrameworkElement view, Point animationDestination,
                                      Duration animationDuration)
        {
            if (!panel.Children.Contains(view)) return;

            var zeroAnimation = new DoubleAnimation(0, animationDuration) {AccelerationRatio = 1};

            Rect viewBoundingBox = GetBoundingBox(view, panel);
            
            var scale = new ScaleTransform(1, 1)
                            {
                                CenterX = view.ActualWidth/2 + (animationDestination.X - viewBoundingBox.Left)/2,
                                CenterY = view.ActualHeight/2 + (animationDestination.Y - viewBoundingBox.Top)/2
                            };

            var group = view.RenderTransform as TransformGroup;
            if (group != null)
                group.Children.Add(scale);
            else
                view.RenderTransform = new TransformGroup {Children = {view.RenderTransform, scale}};

            AnimationViews.Add(zeroAnimation, view);

            view.BeginAnimation(UIElement.OpacityProperty, zeroAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, zeroAnimation);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, zeroAnimation);

            zeroAnimation.CurrentStateInvalidated += AnimationCurrentStateInvalidated;
        }

        private static void AnimationCurrentStateInvalidated(object sender, EventArgs e)
        {
            var da = sender as DoubleAnimation;
            if (da != null)
            {
                FrameworkElement view = AnimationViews[da];
                var parent = view.Parent as Panel;
                if (parent != null) parent.Children.Remove(view);
                AnimationViews.Remove(da);
            }
        }
    }
}